From: Thomas Mueller Date: Fri, 14 Mar 2003 20:46:51 +0000 (+0000) Subject: vol-ro-to-rw-tool-20030314 X-Git-Tag: openafs-devel-1_3_50~313 X-Git-Url: https://git.michaelhowe.org/gitweb/?a=commitdiff_plain;h=8af8241e94284522feb77d75aee8ea3deb73f3cc;p=packages%2Fo%2Fopenafs.git vol-ro-to-rw-tool-20030314 FIXES 1262 allow converting an ro to an rw on namei servers --- diff --git a/src/vol/namei_ops.c b/src/vol/namei_ops.c index 350c47669..ff3fc2bc6 100644 --- a/src/vol/namei_ops.c +++ b/src/vol/namei_ops.c @@ -42,6 +42,7 @@ RCSID("$Header$"); #include "viceinode.h" #include "voldefs.h" #include "partition.h" +#include extern char *volutil_PartitionName_r(int volid, char *buf, int buflen); @@ -1462,7 +1463,213 @@ static int DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info, } return 0; } +/* + * Convert the VolumeInfo file from RO to RW + * this routine is called by namei_convertROtoRWvolume() + */ + +static afs_int32 convertVolumeInfo(fdr, fdw, vid) + int fdr; + int fdw; + afs_uint32 vid; +{ + struct VolumeDiskData vd; + char *p; + + if (read(fdr, &vd, sizeof(struct VolumeDiskData)) != sizeof(struct VolumeDiskData)) { + Log("1 convertVolumeInfo: read failed for %lu with code %d\n", + vid, errno); + return -1; + } + vd.restoredFromId = vd.id; /* remember the RO volume here */ + vd.cloneId = vd.id; + vd.id = vd.parentId; + vd.type = RWVOL; + vd.dontSalvage = 0; + vd.uniquifier += 5000; /* just in case there are still file copies from + the old RW volume around */ + p = strrchr(vd.name, '.'); + if (p && !strcmp(p, ".readonly")) { + bzero(p, 8); + } + if (write(fdw, &vd, sizeof(struct VolumeDiskData)) != sizeof(struct VolumeDiskData)) { + Log("1 convertVolumeInfo: write failed for %lu with code %d\n", + vid, errno); + return -1; + } + return 0; +} + +/* + * Convert a RO-volume into a RW-volume + * + * This function allows to recover very fast from the loss of a partition + * from RO-copies if all RO-Copies exist on another partition. + * Then these RO-volumes can be made to the new RW-volumes. + * Backup of RW-volumes then consists in "vos release". + * + * We must make sure in this partition exists only the RO-volume which + * is typical for remote replicas. + * + * Then the linktable is already ok, + * the vnode files need to be renamed + * the volinfo file needs to be replaced by another one with + * slightly different contents and new name. + * The volume header file of the RO-volume in the /vicep directory + * is destroyed by this call. A new header file for the RW-volume must + * be created after return from this routine. + */ + +int namei_ConvertROtoRWvolume(IHandle_t * h, afs_uint32 vid) +{ + namei_t n; + char dir_name[512], oldpath[512], newpath[512]; + char smallName[64]; + char largeName[64]; + char infoName[64]; + IHandle_t t_ih; + char infoSeen = 0; + char smallSeen = 0; + char largeSeen = 0; + char linkSeen = 0; + int code, fd, fd2; + char *p; + DIR *dirp; + struct dirent *dp; + struct ViceInodeInfo info; + + namei_HandleToName(&n, h); + strcpy(dir_name, n.n_path); + p = strrchr(dir_name, '/'); + *p = 0; + dirp = opendir(dir_name); + if (!dirp) { + Log("1 namei_ConvertROtoRWvolume: Could not opendir(%s)\n", + dir_name); + return EIO; + } + while (dp = readdir(dirp)) { + /* struct ViceInodeInfo info; */ + + if (*dp->d_name == '.') continue; + if (DecodeInode(dir_name, dp->d_name, &info, h->ih_vid)<0) { + Log("1 namei_ConvertROtoRWvolume: DecodeInode failed for %s/%s\n", + dir_name, dp->d_name); + closedir(dirp); + return -1; + } + if (info.u.param[1] != -1) { + Log("1 namei_ConvertROtoRWvolume: found other than volume special file %s/%s\n", + dir_name, dp->d_name); + closedir(dirp); + return -1; + } + if (info.u.param[0] != vid) { + if (info.u.param[0] == h->ih_vid) { + if (info.u.param[2] == VI_LINKTABLE) { /* link table */ + linkSeen = 1; + continue; + } + } + Log("1 namei_ConvertROtoRWvolume: found special file %s/%s for volume %lu\n", + dir_name, dp->d_name, info.u.param[0]); + closedir(dirp); + return VVOLEXISTS; + } + if (info.u.param[2] == VI_VOLINFO) { /* volume info file */ + strcpy(infoName, dp->d_name); + infoSeen = 1; + } + else if (info.u.param[2] == VI_SMALLINDEX) { /* small vnodes file */ + strcpy(smallName, dp->d_name); + smallSeen = 1; + } + else if (info.u.param[2] == VI_LARGEINDEX) { /* large vnodes file */ + strcpy(largeName, dp->d_name); + largeSeen = 1; + } + else { + closedir(dirp); + Log("1 namei_ConvertROtoRWvolume: unknown type %d of special file found : %s/%s\n", + info.u.param[2], dir_name, dp->d_name); + return -1; + } + } + closedir(dirp); + + if (!infoSeen || !smallSeen || !largeSeen || !linkSeen) { + Log("1 namei_ConvertROtoRWvolume: not all special files found in %s\n", + dir_name); + return -1; + } + + /* + * If we come here then there was only a RO-volume and we can safely + * proceed. + */ + + bzero(&t_ih, sizeof(t_ih)); + t_ih.ih_dev = h->ih_dev; + t_ih.ih_vid = h->ih_vid; + + sprintf(oldpath, "%s/%s", dir_name, infoName); + fd = open(oldpath, O_RDWR, 0); + if (fd < 0) { + Log("1 namei_ConvertROtoRWvolume: could not open RO info file: %s\n", + oldpath); + return -1; + } + t_ih.ih_ino = namei_MakeSpecIno(h->ih_vid, VI_VOLINFO); + namei_HandleToName(&n, &t_ih); + fd2 = open(n.n_path, O_CREAT|O_EXCL|O_TRUNC|O_RDWR, 0); + if (fd2 < 0) { + Log("1 namei_ConvertROtoRWvolume: could not create RW info file: %s\n", + n.n_path); + close(fd); + return -1; + } + code = convertVolumeInfo(fd, fd2, h->ih_vid); + close(fd); + if (code) { + close(fd2); + unlink(n.n_path); + return -1; + } + SetOGM(fd2, h->ih_vid, 1); + close(fd2); + + t_ih.ih_ino = namei_MakeSpecIno(h->ih_vid, VI_SMALLINDEX); + namei_HandleToName(&n, &t_ih); + sprintf(newpath, "%s/%s", dir_name, smallName); + fd = open(newpath, O_RDWR, 0); + if (fd < 0) { + Log("1 namei_ConvertROtoRWvolume: could not open SmallIndex file: %s\n", + newpath); + return -1; + } + SetOGM(fd, h->ih_vid, 2); + close(fd); + link(newpath, n.n_path); + unlink(newpath); + + t_ih.ih_ino = namei_MakeSpecIno(h->ih_vid, VI_LARGEINDEX); + namei_HandleToName(&n, &t_ih); + sprintf(newpath, "%s/%s", dir_name, largeName); + fd = open(newpath, O_RDWR, 0); + if (fd < 0) { + Log("1 namei_ConvertROtoRWvolume: could not open LargeIndex file: %s\n", + newpath); + return -1; + } + SetOGM(fd, h->ih_vid, 3); + close(fd); + link(newpath, n.n_path); + unlink(newpath); + + unlink(oldpath); + return 0; +} /* PrintInode * diff --git a/src/volser/volint.xg b/src/volser/volint.xg index 5c36aea18..a4677573c 100644 --- a/src/volser/volint.xg +++ b/src/volser/volint.xg @@ -47,6 +47,7 @@ statindex 16 #define VOLSETINFO 126 #define VOLXLISTPARTITIONS 127 #define VOLFORWARDMULTIPLE 128 +#define VOLCONVERTRO 65536 const SIZE = 1024; @@ -390,3 +391,8 @@ proc ForwardMultiple( IN struct restoreCookie *cookie, OUT manyResults *results ) = VOLFORWARDMULTIPLE; + +proc ConvertROtoRWvolume( + IN afs_int32 partid, + IN afs_int32 volid +) = VOLCONVERTRO; diff --git a/src/volser/volprocs.c b/src/volser/volprocs.c index 7266bf583..1411fbe96 100644 --- a/src/volser/volprocs.c +++ b/src/volser/volprocs.c @@ -2691,6 +2691,113 @@ fail: return error; } +#ifdef AFS_NAMEI_ENV +/* + * Inode number format (from namei_ops.c): + * low 26 bits - vnode number - all 1's if volume special file. + * next 3 bits - tag + * next 3 bits spare (0's) + * high 32 bits - uniquifier (regular) or type if spare + */ +#define NAMEI_VNODEMASK 0x003ffffff +#define NAMEI_TAGMASK 0x7 +#define NAMEI_TAGSHIFT 26 +#define NAMEI_UNIQMASK 0xffffffff +#define NAMEI_UNIQSHIFT 32 +#define NAMEI_INODESPECIAL ((Inode)NAMEI_VNODEMASK) +#define NAMEI_VNODESPECIAL NAMEI_VNODEMASK +#endif /* AFS_NAMEI_ENV */ + +afs_int32 SAFSVolConvertROtoRWvolume(acid, partId, volumeId) + struct rx_call *acid; + afs_int32 partId; + afs_int32 volumeId; +{ +#ifdef AFS_NAMEI_ENV + DIR *dirp; + char pname[16]; + char volname[20]; + afs_int32 error = 0; + afs_int32 volid; + int found = 0; + char caller[MAXKTCNAMELEN]; + char headername[16]; + char opath[256]; + char npath[256]; + struct VolumeDiskHeader h; + int fd; + IHandle_t *ih; + Inode ino; + struct DiskPartition *dp; + + if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;/*not a super user*/ + if(GetPartName(partId, pname)) return VOLSERILLEGAL_PARTITION; + dirp = opendir(pname); + if(dirp == NULL) return VOLSERILLEGAL_PARTITION; + strcpy(volname,""); + + while(strcmp(volname,"EOD") && !found) { /*while there are more volumes in the partition */ + GetNextVol(dirp,volname,&volid); + if(strcmp(volname,"")) {/* its a volume */ + if(volid == volumeId) found = 1; + } + } + if (!found) return ENOENT; + sprintf(headername, VFORMAT, volumeId); + sprintf(opath,"%s/%s", pname, headername); + fd = open(opath, O_RDONLY); + if (fd < 0) { + Log("1 SAFS_VolConvertROtoRWvolume: Couldn't open header for RO-volume %lu.\n", volumeId); + return ENOENT; + } + if (read(fd, &h, sizeof(h)) != sizeof(h)) { + Log("1 SAFS_VolConvertROtoRWvolume: Couldn't read header for RO-volume %lu.\n", volumeId); + close(fd); + return EIO; + } + close(fd); + FSYNC_askfs(volumeId, pname, FSYNC_RESTOREVOLUME, 0); + + for(dp = DiskPartitionList; dp && strcmp(dp->name, pname); dp = dp->next) ; + if (!dp) { + Log("1 SAFS_VolConvertROtoRWvolume: Couldn't find DiskPartition for %s\n", pname); + return EIO; + } + ino = namei_MakeSpecIno(h.parent, VI_LINKTABLE); + IH_INIT(ih, dp->device, h.parent, ino); + + error = namei_ConvertROtoRWvolume(ih, volumeId); + if (error) + return error; + h.id = h.parent; + h.volumeInfo_hi = h.id; + h.smallVnodeIndex_hi = h.id; + h.largeVnodeIndex_hi = h.id; + h.linkTable_hi = h.id; + sprintf(headername, VFORMAT, h.id); + sprintf(npath, "%s/%s", pname, headername); + fd = open(npath, O_CREAT | O_EXCL | O_RDWR, 0644); + if (fd < 0) { + Log("1 SAFS_VolConvertROtoRWvolume: Couldn't create header for RW-volume %lu.\n", h.id); + return EIO; + } + if (write(fd, &h, sizeof(h)) != sizeof(h)) { + Log("1 SAFS_VolConvertROtoRWvolume: Couldn't write header for RW-volume %lu.\n", h.id); + close(fd); + return EIO; + } + close(fd); + if (unlink(opath) < 0) { + Log("1 SAFS_VolConvertROtoRWvolume: Couldn't unlink RO header, error = %d\n", error); + } + FSYNC_askfs(volumeId, pname, FSYNC_DONE, 0); + FSYNC_askfs(h.id, pname, FSYNC_ON, 0); + return 0; +#else /* AFS_NAMEI_ENV */ + return EINVAL; +#endif /* AFS_NAMEI_ENV */ +} + /* GetPartName - map partid (a decimal number) into pname (a string) * Since for NT we actually want to return the drive name, we map through the * partition struct. diff --git a/src/volser/vos.c b/src/volser/vos.c index 3306398fe..81a834b53 100644 --- a/src/volser/vos.c +++ b/src/volser/vos.c @@ -4159,6 +4159,147 @@ register struct cmd_syndesc *as; return 0; } +static ConvertRO(as) +register struct cmd_syndesc *as; + +{ + afs_int32 partition = -1; + afs_int32 server, volid, code, i, same; + struct nvldbentry entry, storeEntry; + afs_int32 vcode; + afs_int32 rwindex; + afs_int32 rwserver = 0; + afs_int32 rwpartition; + afs_int32 roindex; + afs_int32 roserver = 0; + afs_int32 ropartition; + int force = 0; + struct rx_connection *aconn; + char c, dc; + + server = GetServer(as->parms[0].items->data); + if (!server) { + fprintf(STDERR,"vos: host '%s' not found in host table\n",as->parms[0].items->data ); + return ENOENT; + } + partition = volutil_GetPartitionID(as->parms[1].items->data); + if (partition < 0) { + fprintf(STDERR,"vos: could not interpret partition name '%s'\n",as->parms[1].items->data ); + return ENOENT; + } + if (!IsPartValid(partition, server, &code)) { + if(code) PrintError("",code); + else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[1].items->data); + return ENOENT; + } + volid = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &code); + if (volid == 0) { + if (code) PrintError("", code); + else fprintf(STDERR, "Unknown volume ID or name '%s'\n", as->parms[0].items->data); + return -1; + } + if (as->parms[3].items) + force = 1; + + vcode = VLDB_GetEntryByID (volid, -1, &entry); + if(vcode) { + fprintf(STDERR,"Could not fetch the entry for volume %u from VLDB\n", + volid); + PrintError("convertROtoRW", code); + return vcode; + } + + /* use RO volid even if user specified RW or BK volid */ + + if (volid != entry.volumeId[ROVOL]) + volid = entry.volumeId[ROVOL]; + + MapHostToNetwork(&entry); + for (i=0; i< entry.nServers; i++) { + if (entry.serverFlags[i] & ITSRWVOL) { + rwindex = i; + rwserver = entry.serverNumber[i]; + rwpartition = entry.serverPartition[i]; + } + if (entry.serverFlags[i] & ITSROVOL) { + same = VLDB_IsSameAddrs(server, entry.serverNumber[i], &code); + if (code) { + fprintf(STDERR, "Failed to get info about server's %d address(es) from vlserver (err=%d); aborting call!\n", + server, code); + return ENOENT; + } + if (same) { + roindex = i; + roserver = entry.serverNumber[i]; + ropartition = entry.serverPartition[i]; + break; + } + } + } + if (!roserver) { + fprintf(STDERR, "Warning: RO volume didn't exist in vldb!\n"); + } + if (ropartition != partition) { + fprintf(STDERR, "Warning: RO volume should be in partition %d instead of %d (vldb)\n", ropartition, partition); + } + + if (rwserver) { + fprintf(STDERR, + "VLDB indicates that a RW volume exists already on %s in partition %s.\n", hostutil_GetNameByINet(rwserver), volutil_PartitionName(rwpartition)); + if (!force) { + fprintf(STDERR, "Overwrite this VLDB entry? [y|n] (n)\n"); + dc = c = getchar(); + while (!(dc==EOF || dc=='\n')) dc=getchar(); /* goto end of line */ + if ((c != 'y') && (c != 'Y')) { + fprintf(STDERR, "aborted.\n"); + return -1; + } + } + } + + vcode = ubik_Call(VL_SetLock, cstruct, 0, entry.volumeId[RWVOL], RWVOL, + VLOP_MOVE); + aconn = UV_Bind(server, AFSCONF_VOLUMEPORT); + code = AFSVolConvertROtoRWvolume(aconn, partition, volid); + if (code) { + fprintf(STDERR,"Converting RO volume %u to RW volume failed with code %d\n", volid, code); + PrintError("convertROtoRW ", code); + return -1; + } + entry.serverFlags[roindex] = ITSRWVOL; + entry.flags |= RW_EXISTS; + entry.flags &= ~BACK_EXISTS; + if (rwserver) { + (entry.nServers)--; + if (rwindex != entry.nServers) { + entry.serverNumber[rwindex] = entry.serverNumber[entry.nServers]; + entry.serverPartition[rwindex] = entry.serverPartition[entry.nServers]; + entry.serverFlags[rwindex] = entry.serverFlags[entry.nServers]; + entry.serverNumber[entry.nServers] = 0; + entry.serverPartition[entry.nServers] = 0; + entry.serverFlags[entry.nServers] = 0; + } + } + entry.flags &= ~RO_EXISTS; + for (i=0; i