diff --git a/iclient/dev.conf b/iclient/dev.conf index 90990c8b..b1012c88 100644 --- a/iclient/dev.conf +++ b/iclient/dev.conf @@ -13,6 +13,7 @@ FUSEMaxRead: 1048576 FUSEMaxWrite: 1048576 FUSEEntryValidDuration: 250ms FUSEAttrValidDuration: 250ms +FUSENameLenMax: 255 AuthPlugInPath: iauth/iauth-swift/iauth-swift.so AuthPlugInEnvName: AuthPlugInEnvValue: {"AuthURL":"http://swift:8080/auth/v1.0"\u002C"AuthUser":"test:tester"\u002C"AuthKey":"testing"\u002C"Account":"AUTH_test"\u002C"Container":"con"} diff --git a/iclient/iclient.conf b/iclient/iclient.conf index 798341fb..a2f88a59 100644 --- a/iclient/iclient.conf +++ b/iclient/iclient.conf @@ -13,6 +13,7 @@ FUSEMaxRead: 1048576 FUSEMaxWrite: 1048576 FUSEEntryValidDuration: 250ms FUSEAttrValidDuration: 250ms +FUSENameLenMax: 255 AuthPlugInPath: iauth-swift.so AuthPlugInEnvName: AuthPlugInEnvValue: {"AuthURL":"http://swift:8080/auth/v1.0"\u002C"AuthUser":"test:tester"\u002C"AuthKey":"testing"\u002C"Account":"AUTH_test"\u002C"Container":"con"} diff --git a/iclient/iclientpkg/api.go b/iclient/iclientpkg/api.go index 3647aa6d..2ca80da8 100644 --- a/iclient/iclientpkg/api.go +++ b/iclient/iclientpkg/api.go @@ -19,6 +19,7 @@ // FUSEMaxWrite: 1048576 # 1MiB == FUSEMaxPages(256) * 4KiB // FUSEEntryValidDuration: 250ms // FUSEAttrValidDuration: 250ms +// FUSENameLenMax: 255 // AuthPlugInPath: iauth-swift.so // AuthPlugInEnvName: # Only used if not defining AuthPlugInEnvValue here // AuthPlugInEnvValue: {"AuthURL":"http://swift:8080/auth/v1.0"\u002C"AuthUser":"test:tester"\u002C"AuthKey":"testing"\u002C"Account":"AUTH_test"\u002C"Container":"con"} diff --git a/iclient/iclientpkg/fission.go b/iclient/iclientpkg/fission.go index cb4c9187..6de5f71c 100644 --- a/iclient/iclientpkg/fission.go +++ b/iclient/iclientpkg/fission.go @@ -4,6 +4,7 @@ package iclientpkg import ( + "bytes" "container/list" "fmt" "math" @@ -98,6 +99,12 @@ func (dummy *globalsStruct) DoLookup(inHeader *fission.InHeader, lookupIn *fissi globals.stats.DoLookupUsecs.Add(uint64(time.Since(startTime) / time.Microsecond)) }() + errno = checkName(lookupIn.Name) + if errno != 0 { + lookupOut = nil + return + } + Retry: inodeLockRequest = newLockRequest() inodeLockRequest.inodeNumber = inHeader.NodeID @@ -119,10 +126,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - lookupOut = nil - errno = syscall.ENOENT - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -136,10 +140,7 @@ Retry: if nil == inode.payload { err = inode.oldPayload() if nil != err { - inodeLockRequest.unlockAll() - lookupOut = nil - errno = syscall.ENOENT - return + logFatalf("inode.oldPayload() failed: %v", err) } } @@ -244,10 +245,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - getAttrOut = nil - errno = syscall.ENOENT - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -325,10 +323,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - setAttrOut = nil - errno = syscall.ENOENT - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -359,6 +354,7 @@ Retry: if (setAttrIn.Valid & fission.SetAttrInValidSize) != 0 { if setAttrIn.Size != inode.inodeHeadV1.Size { inode.dirty = true + inode.inodeHeadV1.ModificationTime = startTime if setAttrIn.Size < inode.inodeHeadV1.Size { @@ -371,6 +367,7 @@ Retry: inode.unmapExtent(setAttrIn.Size, 0) } + inode.inodeHeadV1.Size = setAttrIn.Size } } @@ -450,10 +447,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - readLinkOut = nil - errno = syscall.ENOENT - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -498,6 +492,14 @@ func (dummy *globalsStruct) DoSymLink(inHeader *fission.InHeader, symLinkIn *fis globals.stats.DoSymLinkUsecs.Add(uint64(time.Since(startTime) / time.Microsecond)) }() + // TODO: Resolve why some (e.g. PJDFSTEST) tests insist .Data length should not be checked + + errno = checkName(symLinkIn.Name) + if errno != 0 { + symLinkOut = nil + return + } + Retry: inodeLockRequest = newLockRequest() inodeLockRequest.inodeNumber = inHeader.NodeID @@ -519,20 +521,14 @@ Retry: if nil == dirInode.inodeHeadV1 { err = dirInode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - symLinkOut = nil - errno = syscall.ENOENT - return + logFatalf("dirInode.populateInodeHeadV1() failed: %v", err) } } if dirInode.payload == nil { err = dirInode.oldPayload() if nil != err { - inodeLockRequest.unlockAll() - symLinkOut = nil - errno = syscall.ENOENT - return + logFatalf("dirInode.oldPayload() failed: %v", err) } } @@ -702,6 +698,12 @@ func (dummy *globalsStruct) DoMkDir(inHeader *fission.InHeader, mkDirIn *fission globals.stats.DoMkDirUsecs.Add(uint64(time.Since(startTime) / time.Microsecond)) }() + errno = checkName(mkDirIn.Name) + if errno != 0 { + mkDirOut = nil + return + } + Retry: inodeLockRequest = newLockRequest() inodeLockRequest.inodeNumber = inHeader.NodeID @@ -723,20 +725,14 @@ Retry: if nil == parentDirInode.inodeHeadV1 { err = parentDirInode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - mkDirOut = nil - errno = syscall.ENOENT - return + logFatalf("parentDirInode.populateInodeHeadV1() failed: %v", err) } } if parentDirInode.payload == nil { err = parentDirInode.oldPayload() if nil != err { - inodeLockRequest.unlockAll() - mkDirOut = nil - errno = syscall.ENOENT - return + logFatalf("parentDirInode.oldPayload() failed: %v", err) } } @@ -931,6 +927,11 @@ func (dummy *globalsStruct) DoUnlink(inHeader *fission.InHeader, unlinkIn *fissi globals.stats.DoUnlinkUsecs.Add(uint64(time.Since(startTime) / time.Microsecond)) }() + errno = checkName(unlinkIn.Name) + if errno != 0 { + return + } + Retry: inodeLockRequest = newLockRequest() inodeLockRequest.inodeNumber = inHeader.NodeID @@ -951,9 +952,7 @@ Retry: if nil == dirInode.inodeHeadV1 { err = dirInode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + logFatalf("dirInode.populateInodeHeadV1() failed: %v", err) } } @@ -966,9 +965,7 @@ Retry: if dirInode.payload == nil { err = dirInode.oldPayload() if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + logFatalf("dirInode.oldPayload() failed: %v", err) } } @@ -1005,9 +1002,7 @@ Retry: if nil == targetInode.inodeHeadV1 { err = targetInode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + logFatalf("targetInode.populateInodeHeadV1() failed: %v", err) } } @@ -1085,6 +1080,11 @@ func (dummy *globalsStruct) DoRmDir(inHeader *fission.InHeader, rmDirIn *fission globals.stats.DoRmDirUsecs.Add(uint64(time.Since(startTime) / time.Microsecond)) }() + errno = checkName(rmDirIn.Name) + if errno != 0 { + return + } + Retry: inodeLockRequest = newLockRequest() inodeLockRequest.inodeNumber = inHeader.NodeID @@ -1105,9 +1105,7 @@ Retry: if nil == parentDirInode.inodeHeadV1 { err = parentDirInode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + logFatalf("parentDirInode.populateInodeHeadV1() failed: %v", err) } } @@ -1120,9 +1118,7 @@ Retry: if parentDirInode.payload == nil { err = parentDirInode.oldPayload() if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + logFatalf("parentDirInode.oldPayload() failed: %v", err) } } @@ -1159,9 +1155,7 @@ Retry: if nil == childDirInode.inodeHeadV1 { err = childDirInode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + logFatalf("childDirInode.populateInodeHeadV1() failed: %v", err) } } @@ -1174,9 +1168,7 @@ Retry: if childDirInode.payload == nil { err = childDirInode.oldPayload() if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + logFatalf("childDirInode.oldPayload() failed: %v", err) } } @@ -1241,6 +1233,15 @@ func (dummy *globalsStruct) DoRename(inHeader *fission.InHeader, renameIn *fissi globals.stats.DoRenameUsecs.Add(uint64(time.Since(startTime) / time.Microsecond)) }() + errno = checkName(renameIn.OldName) + if errno != 0 { + return + } + errno = checkName(renameIn.NewName) + if errno != 0 { + return + } + errno = doRenameCommon(inHeader.NodeID, string(renameIn.OldName[:]), renameIn.NewDir, string(renameIn.NewName[:]), startTime) return } @@ -1264,6 +1265,12 @@ func (dummy *globalsStruct) DoLink(inHeader *fission.InHeader, linkIn *fission.L globals.stats.DoLinkUsecs.Add(uint64(time.Since(startTime) / time.Microsecond)) }() + errno = checkName(linkIn.Name) + if errno != 0 { + linkOut = nil + return + } + Retry: inodeLockRequest = newLockRequest() inodeLockRequest.inodeNumber = inHeader.NodeID @@ -1285,10 +1292,7 @@ Retry: if nil == dirInode.inodeHeadV1 { err = dirInode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - linkOut = nil - errno = syscall.ENOENT - return + logFatalf("dirInode.populateInodeHeadV1() failed: %v", err) } } @@ -1302,10 +1306,7 @@ Retry: if dirInode.payload == nil { err = dirInode.oldPayload() if nil != err { - inodeLockRequest.unlockAll() - linkOut = nil - errno = syscall.ENOENT - return + logFatalf("dirInode.oldPayload() failed: %v", err) } } @@ -1400,6 +1401,7 @@ func (dummy *globalsStruct) DoOpen(inHeader *fission.InHeader, openIn *fission.O err error inode *inodeStruct inodeLockRequest *inodeLockRequestStruct + inodeToBeModified bool openHandle *openHandleStruct startTime time.Time = time.Now() ) @@ -1413,13 +1415,28 @@ func (dummy *globalsStruct) DoOpen(inHeader *fission.InHeader, openIn *fission.O globals.stats.DoOpenUsecs.Add(uint64(time.Since(startTime) / time.Microsecond)) }() - // TODO: Validate simply ignoring openIn.Flags containing fission.FOpenRequestEXCL is ok - // TODO: Need to handle openIn.Flags containing fission.FOpenRequestCREAT + switch openIn.Flags & syscall.O_ACCMODE { + case fission.FOpenRequestRDONLY: + if (openIn.Flags & fission.FOpenRequestTRUNC) == fission.FOpenRequestTRUNC { + openOut = nil + errno = syscall.EINVAL + return + } + inodeToBeModified = false + case fission.FOpenRequestWRONLY: + inodeToBeModified = ((openIn.Flags & fission.FOpenRequestTRUNC) == fission.FOpenRequestTRUNC) + case fission.FOpenRequestRDWR: + inodeToBeModified = ((openIn.Flags & fission.FOpenRequestTRUNC) == fission.FOpenRequestTRUNC) + default: + openOut = nil + errno = syscall.EINVAL + return + } Retry: inodeLockRequest = newLockRequest() inodeLockRequest.inodeNumber = inHeader.NodeID - inodeLockRequest.exclusive = false + inodeLockRequest.exclusive = inodeToBeModified inodeLockRequest.addThisLock() if len(inodeLockRequest.locksHeld) == 0 { performInodeLockRetryDelay() @@ -1437,10 +1454,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - openOut = nil - errno = syscall.ENOENT - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -1459,7 +1473,16 @@ Retry: } } + inode.dirty = true + + inode.inodeHeadV1.ModificationTime = startTime + inode.inodeHeadV1.StatusChangeTime = startTime + inode.unmapExtent(0, 0) + + inode.inodeHeadV1.Size = 0 + + flushInodesInSlice([]*inodeStruct{inode}) } adjustInodeTableEntryOpenCountRequest = &imgrpkg.AdjustInodeTableEntryOpenCountRequestStruct{ @@ -1578,10 +1601,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - readOut = nil - errno = syscall.ENOENT - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -1634,13 +1654,13 @@ Retry: if nil == inode.payload { err = inode.oldPayload() if nil != err { - logFatal(err) + logFatalf("inode.oldPayload() failed: %v", err) } } extentMapEntryIndexV1, _, err = inode.payload.BisectLeft(curOffset) if nil != err { - logFatal(err) + logFatalf("inode.payload.BisectLeft(curOffset) failed: %v", err) } if extentMapEntryIndexV1 < 0 { // Correct for case where curOffset is to the left of the first extent @@ -1999,10 +2019,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - writeOut = nil - errno = syscall.ENOENT - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -2122,6 +2139,7 @@ func (dummy *globalsStruct) DoStatFS(inHeader *fission.InHeader) (statFSOut *fis Files: math.MaxUint64, FFree: math.MaxUint64, BSize: globals.config.FUSEBlockSize, + NameLen: globals.config.FUSENameLenMax, FRSize: globals.config.FUSEBlockSize, Padding: 0, Spare: [6]uint32{0, 0, 0, 0, 0, 0}, @@ -2182,9 +2200,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -2269,9 +2285,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -2329,9 +2343,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -2413,10 +2425,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - getXAttrOut = nil - errno = syscall.ENOENT - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -2501,10 +2510,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - listXAttrOut = nil - errno = syscall.ENOENT - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -2587,9 +2593,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -2712,10 +2716,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - openDirOut = nil - errno = syscall.ENOENT - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -2814,10 +2815,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - readDirOut = nil - errno = syscall.ENOENT - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -2831,10 +2829,7 @@ Retry: if nil == inode.payload { err = inode.oldPayload() if nil != err { - inodeLockRequest.unlockAll() - readDirOut = nil - errno = syscall.ENOENT - return + logFatalf("inode.oldPayload() failed: %v", err) } } @@ -2962,9 +2957,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -3113,6 +3106,12 @@ func (dummy *globalsStruct) DoCreate(inHeader *fission.InHeader, createIn *fissi globals.stats.DoCreateUsecs.Add(uint64(time.Since(startTime) / time.Microsecond)) }() + errno = checkName(createIn.Name) + if errno != 0 { + createOut = nil + return + } + Retry: inodeLockRequest = newLockRequest() inodeLockRequest.inodeNumber = inHeader.NodeID @@ -3134,10 +3133,7 @@ Retry: if nil == dirInode.inodeHeadV1 { err = dirInode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - createOut = nil - errno = syscall.ENOENT - return + logFatalf("dirInode.populateInodeHeadV1() failed: %v", err) } } @@ -3151,10 +3147,7 @@ Retry: if dirInode.payload == nil { err = dirInode.oldPayload() if nil != err { - inodeLockRequest.unlockAll() - createOut = nil - errno = syscall.ENOENT - return + logFatalf("dirInode.oldPayload() failed: %v", err) } } @@ -3501,10 +3494,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - readDirPlusOut = nil - errno = syscall.ENOENT - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -3518,10 +3508,7 @@ Retry: if nil == inode.payload { err = inode.oldPayload() if nil != err { - inodeLockRequest.unlockAll() - readDirPlusOut = nil - errno = syscall.ENOENT - return + logFatalf("inode.oldPayload() failed: %v", err) } } @@ -3641,6 +3628,15 @@ func (dummy *globalsStruct) DoRename2(inHeader *fission.InHeader, rename2In *fis globals.stats.DoRename2Usecs.Add(uint64(time.Since(startTime) / time.Microsecond)) }() + errno = checkName(rename2In.OldName) + if errno != 0 { + return + } + errno = checkName(rename2In.NewName) + if errno != 0 { + return + } + errno = doRenameCommon(inHeader.NodeID, string(rename2In.OldName[:]), rename2In.NewDir, string(rename2In.NewName[:]), startTime) return } @@ -3740,9 +3736,7 @@ Retry: if nil == inode.inodeHeadV1 { err = inode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - err = fmt.Errorf("inode.populateInodeHeadV1() failed: %v", err) - return + logFatalf("inode.populateInodeHeadV1() failed: %v", err) } } @@ -3797,6 +3791,20 @@ func fixAttrSizes(attr *fission.Attr) { } } +func checkName(name []byte) (errno syscall.Errno) { + if bytes.Compare(name, []byte{'.'}) == 0 { + errno = syscall.EINVAL + } else if bytes.Compare(name, []byte{'.', '.'}) == 0 { + errno = syscall.EINVAL + } else if len(name) > int(globals.config.FUSENameLenMax) { + errno = syscall.ENAMETOOLONG + } else { + errno = 0 + } + + return +} + func doRenameCommon(oldDirInodeNumber uint64, oldName string, newDirInodeNumber uint64, newName string, startTime time.Time) (errno syscall.Errno) { var ( deleteInodeTableEntryRequest *imgrpkg.DeleteInodeTableEntryRequestStruct @@ -3810,6 +3818,7 @@ func doRenameCommon(oldDirInodeNumber uint64, oldName string, newDirInodeNumber oldDirInode *inodeStruct renamedInode *inodeStruct replacedInode *inodeStruct + replacedInodePayloadLen int ) Retry: @@ -3832,9 +3841,7 @@ Retry: if nil == oldDirInode.inodeHeadV1 { err = oldDirInode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + logFatalf("oldDirInode.populateInodeHeadV1() failed: %v", err) } } @@ -3847,9 +3854,7 @@ Retry: if oldDirInode.payload == nil { err = oldDirInode.oldPayload() if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + logFatalf("oldDirInode.oldPayload() failed: %v", err) } } @@ -3885,9 +3890,7 @@ Retry: if nil == renamedInode.inodeHeadV1 { err = renamedInode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + logFatalf("renamedInode.populateInodeHeadV1() failed: %v", err) } } @@ -3923,18 +3926,14 @@ Retry: if nil == newDirInode.inodeHeadV1 { err = newDirInode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + logFatalf("newDirInode.populateInodeHeadV1() failed: %v", err) } } if newDirInode.payload == nil { err = newDirInode.oldPayload() if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + logFatalf("newDirInode.oldPayload() failed: %v", err) } } } @@ -3967,116 +3966,143 @@ Retry: if nil == replacedInode.inodeHeadV1 { err = replacedInode.populateInodeHeadV1() if nil != err { - inodeLockRequest.unlockAll() - goto Retry + logFatalf("replacedInode.populateInodeHeadV1() failed: %v", err) } } - if replacedInode.inodeHeadV1.InodeType == ilayout.InodeTypeDir { - inodeLockRequest.unlockAll() - errno = syscall.EISDIR - return + if renamedInode.inodeHeadV1.InodeType == ilayout.InodeTypeDir { + if replacedInode.inodeHeadV1.InodeType == ilayout.InodeTypeDir { + if replacedInode.payload == nil { + err = replacedInode.oldPayload() + if nil != err { + logFatalf("replacedInode.oldPayload() failed: %v", err) + } + } + + replacedInodePayloadLen, err = replacedInode.payload.Len() + if nil != err { + logFatalf("replacedInode.payload.Len() failed: %v", err) + } + if replacedInodePayloadLen != 2 { + inodeLockRequest.unlockAll() + errno = syscall.ENOTEMPTY + return + } + } else { // replacedInode.inodeHeadV1.InodeType != ilayout.InodeTypeDir + inodeLockRequest.unlockAll() + errno = syscall.ENOTDIR + return + } + } else { // renamedInode.inodeHeadV1.InodeType != ilayout.InodeTypeDir + if replacedInode.inodeHeadV1.InodeType == ilayout.InodeTypeDir { + inodeLockRequest.unlockAll() + errno = syscall.EISDIR + return + } } } else { replacedInode = nil } if renamedInode.inodeHeadV1.InodeType == ilayout.InodeTypeDir { - if replacedInode != nil { - inodeLockRequest.unlockAll() - errno = syscall.EISDIR - return - } - - if renamedInode.payload == nil { - err = renamedInode.oldPayload() - if nil != err { - inodeLockRequest.unlockAll() - errno = syscall.ENOENT - return + if replacedInode == nil { + if renamedInode.payload == nil { + err = renamedInode.oldPayload() + if nil != err { + logFatalf("renamedInode.oldPayload() failed: %v", err) + } } - } - renamedInode.dirty = true + renamedInode.dirty = true - renamedInode.inodeHeadV1.ModificationTime = startTime - renamedInode.inodeHeadV1.StatusChangeTime = startTime + renamedInode.inodeHeadV1.ModificationTime = startTime + renamedInode.inodeHeadV1.StatusChangeTime = startTime - delete(renamedInode.linkSet, ilayout.InodeLinkTableEntryStruct{ - ParentDirInodeNumber: oldDirInodeNumber, - ParentDirEntryName: oldName, - }) + delete(renamedInode.linkSet, ilayout.InodeLinkTableEntryStruct{ + ParentDirInodeNumber: oldDirInodeNumber, + ParentDirEntryName: oldName, + }) - renamedInode.linkSet[ilayout.InodeLinkTableEntryStruct{ - ParentDirInodeNumber: newDirInodeNumber, - ParentDirEntryName: newName, - }] = struct{}{} + renamedInode.linkSet[ilayout.InodeLinkTableEntryStruct{ + ParentDirInodeNumber: newDirInodeNumber, + ParentDirEntryName: newName, + }] = struct{}{} - ok, err = renamedInode.payload.PatchByKey( - "..", - &ilayout.DirectoryEntryValueV1Struct{ - InodeNumber: newDirInodeNumber, - InodeType: ilayout.InodeTypeDir, - }) - if nil != err { - logFatalf("renamedInode.payload.PatchByKey(\"..\",) failed: %v", err) - } - if !ok { - logFatalf("renamedInode.payload.PatchByKey(\"..\",) returned !ok") - } + ok, err = renamedInode.payload.PatchByKey( + "..", + &ilayout.DirectoryEntryValueV1Struct{ + InodeNumber: newDirInodeNumber, + InodeType: ilayout.InodeTypeDir, + }) + if nil != err { + logFatalf("renamedInode.payload.PatchByKey(\"..\",) failed: %v", err) + } + if !ok { + logFatalf("renamedInode.payload.PatchByKey(\"..\",) returned !ok") + } - oldDirInode.dirty = true + oldDirInode.dirty = true - oldDirInode.inodeHeadV1.ModificationTime = startTime - oldDirInode.inodeHeadV1.StatusChangeTime = startTime + oldDirInode.inodeHeadV1.ModificationTime = startTime + oldDirInode.inodeHeadV1.StatusChangeTime = startTime - delete(oldDirInode.linkSet, ilayout.InodeLinkTableEntryStruct{ - ParentDirInodeNumber: renamedInode.inodeNumber, - ParentDirEntryName: oldName, - }) + delete(oldDirInode.linkSet, ilayout.InodeLinkTableEntryStruct{ + ParentDirInodeNumber: renamedInode.inodeNumber, + ParentDirEntryName: "..", + }) - ok, err = oldDirInode.payload.DeleteByKey(oldName) - if nil != err { - logFatalf("oldDirInode.payload.DeleteByKey(oldName) failed: %v", err) - } - if !ok { - logFatalf("oldDirInode.payload.DeleteByKey(oldName) returned !ok") - } + ok, err = oldDirInode.payload.DeleteByKey(oldName) + if nil != err { + logFatalf("oldDirInode.payload.DeleteByKey(oldName) failed: %v", err) + } + if !ok { + logFatalf("oldDirInode.payload.DeleteByKey(oldName) returned !ok") + } - newDirInode.dirty = true + newDirInode.dirty = true - newDirInode.inodeHeadV1.ModificationTime = startTime - newDirInode.inodeHeadV1.StatusChangeTime = startTime + newDirInode.inodeHeadV1.ModificationTime = startTime + newDirInode.inodeHeadV1.StatusChangeTime = startTime - newDirInode.linkSet[ilayout.InodeLinkTableEntryStruct{ - ParentDirInodeNumber: renamedInode.inodeNumber, - ParentDirEntryName: "..", - }] = struct{}{} + newDirInode.linkSet[ilayout.InodeLinkTableEntryStruct{ + ParentDirInodeNumber: renamedInode.inodeNumber, + ParentDirEntryName: "..", + }] = struct{}{} - ok, err = newDirInode.payload.Put( - newName, - &ilayout.DirectoryEntryValueV1Struct{ - InodeNumber: renamedInode.inodeNumber, - InodeType: ilayout.InodeTypeDir, - }) - if nil != err { - logFatalf("newDirInode.payload.Put(newName,) failed: %v", err) - } - if !ok { - logFatalf("newDirInode.payload.Put(newName,) returned !ok") - } - } else { - if replacedInode != nil { + ok, err = newDirInode.payload.Put( + newName, + &ilayout.DirectoryEntryValueV1Struct{ + InodeNumber: renamedInode.inodeNumber, + InodeType: ilayout.InodeTypeDir, + }) + if nil != err { + logFatalf("newDirInode.payload.Put(newName,) failed: %v", err) + } + if !ok { + logFatalf("newDirInode.payload.Put(newName,) returned !ok") + } + } else { // replacedInode != nil replacedInode.dirty = true replacedInode.inodeHeadV1.ModificationTime = startTime replacedInode.inodeHeadV1.StatusChangeTime = startTime + delete(replacedInode.linkSet, ilayout.InodeLinkTableEntryStruct{ + ParentDirInodeNumber: replacedInode.inodeNumber, + ParentDirEntryName: ".", + }) delete(replacedInode.linkSet, ilayout.InodeLinkTableEntryStruct{ ParentDirInodeNumber: newDirInodeNumber, ParentDirEntryName: newName, }) + if renamedInode.payload == nil { + err = renamedInode.oldPayload() + if nil != err { + logFatalf("renamedInode.oldPayload() failed: %v", err) + } + } + renamedInode.dirty = true renamedInode.inodeHeadV1.ModificationTime = startTime @@ -4092,11 +4118,29 @@ Retry: ParentDirEntryName: newName, }] = struct{}{} + ok, err = renamedInode.payload.PatchByKey( + "..", + &ilayout.DirectoryEntryValueV1Struct{ + InodeNumber: newDirInodeNumber, + InodeType: ilayout.InodeTypeDir, + }) + if nil != err { + logFatalf("renamedInode.payload.PatchByKey(\"..\",) failed: %v", err) + } + if !ok { + logFatalf("renamedInode.payload.PatchByKey(\"..\",) returned !ok") + } + oldDirInode.dirty = true oldDirInode.inodeHeadV1.ModificationTime = startTime oldDirInode.inodeHeadV1.StatusChangeTime = startTime + delete(oldDirInode.linkSet, ilayout.InodeLinkTableEntryStruct{ + ParentDirInodeNumber: renamedInode.inodeNumber, + ParentDirEntryName: "..", + }) + ok, err = oldDirInode.payload.DeleteByKey(oldName) if nil != err { logFatalf("oldDirInode.payload.DeleteByKey(oldName) failed: %v", err) @@ -4110,6 +4154,15 @@ Retry: newDirInode.inodeHeadV1.ModificationTime = startTime newDirInode.inodeHeadV1.StatusChangeTime = startTime + delete(newDirInode.linkSet, ilayout.InodeLinkTableEntryStruct{ + ParentDirInodeNumber: replacedInode.inodeNumber, + ParentDirEntryName: "..", + }) + newDirInode.linkSet[ilayout.InodeLinkTableEntryStruct{ + ParentDirInodeNumber: renamedInode.inodeNumber, + ParentDirEntryName: "..", + }] = struct{}{} + ok, err = newDirInode.payload.PatchByKey( newName, &ilayout.DirectoryEntryValueV1Struct{ @@ -4122,7 +4175,9 @@ Retry: if !ok { logFatalf("newDirInode.payload.PatchByKey(newName,) returned !ok") } - } else { + } + } else { // renamedInode.inodeHeadV1.InodeType != ilayout.InodeTypeDir + if replacedInode == nil { renamedInode.dirty = true renamedInode.inodeHeadV1.ModificationTime = startTime @@ -4168,6 +4223,62 @@ Retry: if !ok { logFatalf("newDirInode.payload.Put(newName,) returned !ok") } + } else { // replacedInode != nil + replacedInode.dirty = true + + replacedInode.inodeHeadV1.ModificationTime = startTime + replacedInode.inodeHeadV1.StatusChangeTime = startTime + + delete(replacedInode.linkSet, ilayout.InodeLinkTableEntryStruct{ + ParentDirInodeNumber: newDirInodeNumber, + ParentDirEntryName: newName, + }) + + renamedInode.dirty = true + + renamedInode.inodeHeadV1.ModificationTime = startTime + renamedInode.inodeHeadV1.StatusChangeTime = startTime + + delete(renamedInode.linkSet, ilayout.InodeLinkTableEntryStruct{ + ParentDirInodeNumber: oldDirInodeNumber, + ParentDirEntryName: oldName, + }) + + renamedInode.linkSet[ilayout.InodeLinkTableEntryStruct{ + ParentDirInodeNumber: newDirInodeNumber, + ParentDirEntryName: newName, + }] = struct{}{} + + oldDirInode.dirty = true + + oldDirInode.inodeHeadV1.ModificationTime = startTime + oldDirInode.inodeHeadV1.StatusChangeTime = startTime + + ok, err = oldDirInode.payload.DeleteByKey(oldName) + if nil != err { + logFatalf("oldDirInode.payload.DeleteByKey(oldName) failed: %v", err) + } + if !ok { + logFatalf("oldDirInode.payload.DeleteByKey(oldName) returned !ok") + } + + newDirInode.dirty = true + + newDirInode.inodeHeadV1.ModificationTime = startTime + newDirInode.inodeHeadV1.StatusChangeTime = startTime + + ok, err = newDirInode.payload.PatchByKey( + newName, + &ilayout.DirectoryEntryValueV1Struct{ + InodeNumber: renamedInode.inodeNumber, + InodeType: ilayout.InodeTypeDir, + }) + if nil != err { + logFatalf("newDirInode.payload.PatchByKey(newName,) failed: %v", err) + } + if !ok { + logFatalf("newDirInode.payload.PatchByKey(newName,) returned !ok") + } } } diff --git a/iclient/iclientpkg/globals.go b/iclient/iclientpkg/globals.go index 6f63df37..4cdd0f7d 100644 --- a/iclient/iclientpkg/globals.go +++ b/iclient/iclientpkg/globals.go @@ -34,6 +34,7 @@ type configStruct struct { FUSEMaxWrite uint32 FUSEEntryValidDuration time.Duration FUSEAttrValidDuration time.Duration + FUSENameLenMax uint32 AuthPlugInPath string AuthPlugInEnvName string AuthPlugInEnvValue string @@ -334,6 +335,10 @@ func initializeGlobals(confMap conf.ConfMap, fissionErrChan chan error) (err err if nil != err { logFatal(err) } + globals.config.FUSENameLenMax, err = confMap.FetchOptionValueUint32("ICLIENT", "FUSENameLenMax") + if nil != err { + logFatal(err) + } globals.config.AuthPlugInPath, err = confMap.FetchOptionValueString("ICLIENT", "AuthPlugInPath") if nil != err { logFatal(err) @@ -562,6 +567,7 @@ func uninitializeGlobals() (err error) { globals.config.FUSEMaxWrite = 0 globals.config.FUSEEntryValidDuration = time.Duration(0) globals.config.FUSEAttrValidDuration = time.Duration(0) + globals.config.FUSENameLenMax = 0 globals.config.AuthPlugInPath = "" globals.config.AuthPlugInEnvName = "" globals.config.AuthPlugInEnvValue = "" diff --git a/iclient/iclientpkg/utils_test.go b/iclient/iclientpkg/utils_test.go index b831c233..4e18caa1 100644 --- a/iclient/iclientpkg/utils_test.go +++ b/iclient/iclientpkg/utils_test.go @@ -141,6 +141,7 @@ func testSetup(t *testing.T) { "ICLIENT.FUSEMaxWrite=1048576", "ICLIENT.FUSEEntryValidDuration=250ms", "ICLIENT.FUSEAttrValidDuration=250ms", + "ICLIENT.FUSENameLenMax=255", "ICLIENT.AuthPlugInPath=../../iauth/iauth-swift/iauth-swift.so", "ICLIENT.AuthPlugInEnvName=", "ICLIENT.AuthPlugInEnvValue=" + fmt.Sprintf("{\"AuthURL\":\"http://%s:%d/auth/v1.0\"\\u002C\"AuthUser\":\"%s\"\\u002C\"AuthKey\":\"%s\"\\u002C\"Account\":\"%s\"\\u002C\"Container\":\"%s\"}", testIPAddr, testSwiftProxyTCPPort, testSwiftAuthUser, testSwiftAuthKey, testAccount, testContainer), @@ -194,6 +195,7 @@ func testSetup(t *testing.T) { "IMGR.FetchNonceRangeToReturn=100", + "IMGR.MountLimit=10000", "IMGR.OpenFileLimit=100000", "IMGR.MinLeaseDuration=250ms", diff --git a/imgr/dev.conf b/imgr/dev.conf index d223e200..b1567e91 100644 --- a/imgr/dev.conf +++ b/imgr/dev.conf @@ -30,6 +30,7 @@ AuthTokenCheckInterval: 1m FetchNonceRangeToReturn: 100 +MountLimit: 10000 OpenFileLimit: 100000 MinLeaseDuration: 250ms diff --git a/imgr/imgr.conf b/imgr/imgr.conf index 72c723d6..917540ee 100644 --- a/imgr/imgr.conf +++ b/imgr/imgr.conf @@ -30,6 +30,7 @@ AuthTokenCheckInterval: 1m FetchNonceRangeToReturn: 100 +MountLimit: 10000 OpenFileLimit: 100000 MinLeaseDuration: 250ms diff --git a/imgr/imgrpkg/api.go b/imgr/imgrpkg/api.go index 8c55888c..df4d5149 100644 --- a/imgr/imgrpkg/api.go +++ b/imgr/imgrpkg/api.go @@ -43,6 +43,7 @@ // // FetchNonceRangeToReturn: 100 // +// MountLimit: 10000 // OpenFileLimit: 100000 // // MinLeaseDuration: 250ms @@ -198,13 +199,12 @@ const ( EBadOpenCountAdjustment = "EBadOpenCountAdjustment:" ELeaseRequestDenied = "ELeaseRequestDenied:" EMissingLease = "EMissingLease:" + ETooManyMounts = "ETooManyMounts" ETooManyOpens = "ETooManyOpens" EVolumeBeingDeleted = "EVolumeBeingDeleted:" EUnknownInodeNumber = "EUnknownInodeNumber:" EUnknownMountID = "EUnknownMountID:" EUnknownVolumeName = "EUnknownVolumeName:" - - ETODO = "ETODO:" ) type RetryRPCServerStruct struct{} diff --git a/imgr/imgrpkg/globals.go b/imgr/imgrpkg/globals.go index 35666bc6..cb4cb142 100644 --- a/imgr/imgrpkg/globals.go +++ b/imgr/imgrpkg/globals.go @@ -50,6 +50,7 @@ type configStruct struct { FetchNonceRangeToReturn uint64 + MountLimit uint64 OpenFileLimit uint64 MinLeaseDuration time.Duration @@ -220,7 +221,7 @@ type mountStruct struct { volume *volumeStruct // mountID string // retryRPCClientID uint64 // - unmounting bool // + unmountWGList *list.List // if nil, not currently unmounting; if non-nil, elements are *sync.WaitGroup of any unmount waiters leaseRequestMap map[uint64]*leaseRequestStruct // key == leaseRequestStruct.inodeLease.inodeNumber authToken string // lastAuthTime time.Time // used to periodically check TTL of authToken @@ -279,6 +280,7 @@ type globalsStruct struct { inodeLeaseExpirerWG *sync.WaitGroup // != nil means there is an inodeLeaseExpirer running volumeMap sortedmap.LLRBTree // key == volumeStruct.name; value == *volumeStruct mountMap map[string]*mountStruct // key == mountStruct.mountID + unmountsInProgress uint64 // checkPointHTTPClient *http.Client // checkPointURL []string // swiftHTTPClient *http.Client // @@ -557,6 +559,10 @@ func initializeGlobals(confMap conf.ConfMap) (err error) { logFatal(err) } + globals.config.MountLimit, err = confMap.FetchOptionValueUint64("IMGR", "MountLimit") + if nil != err { + logFatal(err) + } globals.config.OpenFileLimit, err = confMap.FetchOptionValueUint64("IMGR", "OpenFileLimit") if nil != err { logFatal(err) @@ -691,6 +697,7 @@ func uninitializeGlobals() (err error) { globals.config.FetchNonceRangeToReturn = 0 + globals.config.MountLimit = 0 globals.config.OpenFileLimit = 0 globals.config.MinLeaseDuration = time.Duration(0) diff --git a/imgr/imgrpkg/http-server.go b/imgr/imgrpkg/http-server.go index 8b04703f..191ccc07 100644 --- a/imgr/imgrpkg/http-server.go +++ b/imgr/imgrpkg/http-server.go @@ -1307,9 +1307,11 @@ type serveHTTPPostOfVolumeRequestBodyAsJSONStruct struct { func serveHTTPPostOfVolume(responseWriter http.ResponseWriter, request *http.Request, requestBody []byte) { var ( - err error - requestBodyAsJSON serveHTTPPostOfVolumeRequestBodyAsJSONStruct - startTime time.Time = time.Now() + conflictReason []byte + confligtReasonWriteErr error + err error + requestBodyAsJSON serveHTTPPostOfVolumeRequestBodyAsJSONStruct + startTime time.Time = time.Now() ) defer func() { @@ -1326,7 +1328,17 @@ func serveHTTPPostOfVolume(responseWriter http.ResponseWriter, request *http.Req if nil == err { responseWriter.WriteHeader(http.StatusCreated) } else { + conflictReason = []byte(fmt.Sprintf("%v\n", err)) + + responseWriter.Header().Set("Content-Length", fmt.Sprintf("%d", len(conflictReason))) + responseWriter.Header().Set("Content-Type", "text/html") + responseWriter.WriteHeader(http.StatusConflict) + + _, confligtReasonWriteErr = responseWriter.Write(conflictReason) + if nil != confligtReasonWriteErr { + logWarnf("responseWriter.Write(conflictReason) failed: %v", confligtReasonWriteErr) + } } } @@ -1346,10 +1358,12 @@ type serveHTTPPutOfVolumeRequestBodyAsJSONStruct struct { func serveHTTPPutOfVolume(responseWriter http.ResponseWriter, request *http.Request, requestPath string, requestBody []byte) { var ( - err error - pathSplit []string - requestBodyAsJSON serveHTTPPutOfVolumeRequestBodyAsJSONStruct - startTime time.Time = time.Now() + conflictReason []byte + confligtReasonWriteErr error + err error + pathSplit []string + requestBodyAsJSON serveHTTPPutOfVolumeRequestBodyAsJSONStruct + startTime time.Time = time.Now() ) pathSplit = strings.Split(requestPath, "/") @@ -1370,7 +1384,17 @@ func serveHTTPPutOfVolume(responseWriter http.ResponseWriter, request *http.Requ if nil == err { responseWriter.WriteHeader(http.StatusCreated) } else { + conflictReason = []byte(fmt.Sprintf("%v\n", err)) + + responseWriter.Header().Set("Content-Length", fmt.Sprintf("%d", len(conflictReason))) + responseWriter.Header().Set("Content-Type", "text/html") + responseWriter.WriteHeader(http.StatusConflict) + + _, confligtReasonWriteErr = responseWriter.Write(conflictReason) + if nil != confligtReasonWriteErr { + logWarnf("responseWriter.Write(conflictReason) failed: %v", confligtReasonWriteErr) + } } default: responseWriter.WriteHeader(http.StatusBadRequest) diff --git a/imgr/imgrpkg/lease.go b/imgr/imgrpkg/lease.go index d783737c..200dd1bc 100644 --- a/imgr/imgrpkg/lease.go +++ b/imgr/imgrpkg/lease.go @@ -825,10 +825,12 @@ func (inodeLease *inodeLeaseStruct) handleInterruptTimerPop() { delete(leaseRequest.mount.leaseRequestMap, inodeLease.inodeNumber) - if !leaseRequest.mount.unmounting { - leaseRequest.mount.unmounting = true + if leaseRequest.mount.unmountWGList == nil { + leaseRequest.mount.unmountWGList = list.New() - go leaseRequest.mount.performUnmount(nil) + globals.unmountsInProgress++ + + go leaseRequest.mount.performUnmount() } inodeLease.releasingHoldersList.Remove(leaseRequestElement) @@ -858,10 +860,12 @@ func (inodeLease *inodeLeaseStruct) handleInterruptTimerPop() { delete(leaseRequest.mount.leaseRequestMap, inodeLease.inodeNumber) - if !leaseRequest.mount.unmounting { - leaseRequest.mount.unmounting = true + if leaseRequest.mount.unmountWGList == nil { + leaseRequest.mount.unmountWGList = list.New() + + globals.unmountsInProgress++ - go leaseRequest.mount.performUnmount(nil) + go leaseRequest.mount.performUnmount() } inodeLease.releasingHoldersList.Remove(leaseRequestElement) @@ -898,10 +902,12 @@ func (inodeLease *inodeLeaseStruct) handleInterruptTimerPop() { delete(inodeLease.demotingHolder.mount.leaseRequestMap, inodeLease.inodeNumber) - if !inodeLease.demotingHolder.mount.unmounting { - inodeLease.demotingHolder.mount.unmounting = true + if inodeLease.demotingHolder.mount.unmountWGList == nil { + inodeLease.demotingHolder.mount.unmountWGList = list.New() - go inodeLease.demotingHolder.mount.performUnmount(nil) + globals.unmountsInProgress++ + + go inodeLease.demotingHolder.mount.performUnmount() } inodeLease.demotingHolder = nil @@ -948,10 +954,12 @@ func (inodeLease *inodeLeaseStruct) handleInterruptTimerPop() { delete(leaseRequest.mount.leaseRequestMap, inodeLease.inodeNumber) - if !leaseRequest.mount.unmounting { - leaseRequest.mount.unmounting = true + if leaseRequest.mount.unmountWGList == nil { + leaseRequest.mount.unmountWGList = list.New() + + globals.unmountsInProgress++ - go leaseRequest.mount.performUnmount(nil) + go leaseRequest.mount.performUnmount() } inodeLease.releasingHoldersList.Remove(leaseRequestElement) diff --git a/imgr/imgrpkg/retry-rpc.go b/imgr/imgrpkg/retry-rpc.go index 25ba3da7..c0508f7e 100644 --- a/imgr/imgrpkg/retry-rpc.go +++ b/imgr/imgrpkg/retry-rpc.go @@ -107,6 +107,12 @@ func mount(retryRPCClientID uint64, mountRequest *MountRequestStruct, mountRespo globals.Lock() + if (uint64(len(globals.mountMap)) - globals.unmountsInProgress) >= globals.config.MountLimit { + globals.Unlock() + err = fmt.Errorf("%s", ETooManyMounts) + return + } + volumeAsValue, ok, err = globals.volumeMap.GetByKey(mountRequest.VolumeName) if nil != err { logFatalf("globals.volumeMap.GetByKey() failed: %v", err) @@ -162,7 +168,7 @@ retryGenerateMountID: volume: volume, mountID: mountIDAsString, retryRPCClientID: retryRPCClientID, - unmounting: false, + unmountWGList: nil, leaseRequestMap: make(map[uint64]*leaseRequestStruct), authToken: mountRequest.AuthToken, lastAuthTime: startTime, @@ -244,7 +250,7 @@ func renewMount(renewMountRequest *RenewMountRequestStruct, renewMountResponse * globals.Lock() mount, ok = globals.mountMap[renewMountRequest.MountID] - if !ok || mount.unmounting { + if !ok || (mount.unmountWGList != nil) { globals.Unlock() err = fmt.Errorf("%s %s", EUnknownMountID, renewMountRequest.MountID) return @@ -309,17 +315,20 @@ func unmount(unmountRequest *UnmountRequestStruct, unmountResponse *UnmountRespo globals.Lock() mount, ok = globals.mountMap[unmountRequest.MountID] - if !ok || mount.unmounting { + if !ok || (mount.unmountWGList != nil) { globals.Unlock() err = fmt.Errorf("%s %s", EUnknownMountID, unmountRequest.MountID) return } - mount.unmounting = true + mount.unmountWGList = list.New() unmountFinishedWG.Add(1) + _ = mount.unmountWGList.PushBack(&unmountFinishedWG) + + globals.unmountsInProgress++ - go mount.performUnmount(&unmountFinishedWG) + go mount.performUnmount() globals.Unlock() @@ -356,7 +365,7 @@ func volumeStatus(volumeStatusRequest *VolumeStatusRequestStruct, volumeStatusRe globals.Lock() mount, ok = globals.mountMap[volumeStatusRequest.MountID] - if !ok || mount.unmounting { + if !ok || (mount.unmountWGList != nil) { globals.Unlock() err = fmt.Errorf("%s %s", EUnknownMountID, volumeStatusRequest.MountID) return @@ -403,7 +412,7 @@ func fetchNonceRange(fetchNonceRangeRequest *FetchNonceRangeRequestStruct, fetch globals.Lock() mount, ok = globals.mountMap[fetchNonceRangeRequest.MountID] - if !ok || mount.unmounting { + if !ok || (mount.unmountWGList != nil) { globals.Unlock() err = fmt.Errorf("%s %s", EUnknownMountID, fetchNonceRangeRequest.MountID) return @@ -449,7 +458,7 @@ func getInodeTableEntry(getInodeTableEntryRequest *GetInodeTableEntryRequestStru globals.Lock() mount, ok = globals.mountMap[getInodeTableEntryRequest.MountID] - if !ok || mount.unmounting { + if !ok || (mount.unmountWGList != nil) { globals.Unlock() err = fmt.Errorf("%s %s", EUnknownMountID, getInodeTableEntryRequest.MountID) return @@ -522,7 +531,7 @@ func putInodeTableEntries(putInodeTableEntriesRequest *PutInodeTableEntriesReque globals.Lock() mount, ok = globals.mountMap[putInodeTableEntriesRequest.MountID] - if !ok || mount.unmounting { + if !ok || (mount.unmountWGList != nil) { globals.Unlock() err = fmt.Errorf("%s %s", EUnknownMountID, putInodeTableEntriesRequest.MountID) return @@ -607,7 +616,7 @@ func deleteInodeTableEntry(deleteInodeTableEntryRequest *DeleteInodeTableEntryRe globals.Lock() mount, ok = globals.mountMap[deleteInodeTableEntryRequest.MountID] - if !ok || mount.unmounting { + if !ok || (mount.unmountWGList != nil) { globals.Unlock() err = fmt.Errorf("%s %s", EUnknownMountID, deleteInodeTableEntryRequest.MountID) return @@ -670,7 +679,7 @@ func adjustInodeTableEntryOpenCount(adjustInodeTableEntryOpenCountRequest *Adjus globals.Lock() mount, ok = globals.mountMap[adjustInodeTableEntryOpenCountRequest.MountID] - if !ok || mount.unmounting { + if !ok || (mount.unmountWGList != nil) { globals.Unlock() err = fmt.Errorf("%s %s", EUnknownMountID, adjustInodeTableEntryOpenCountRequest.MountID) return @@ -790,7 +799,7 @@ func flush(flushRequest *FlushRequestStruct, flushResponse *FlushResponseStruct) globals.Lock() mount, ok = globals.mountMap[flushRequest.MountID] - if !ok || mount.unmounting { + if !ok || (mount.unmountWGList != nil) { globals.Unlock() err = fmt.Errorf("%s %s", EUnknownMountID, flushRequest.MountID) return @@ -872,7 +881,7 @@ func lease(leaseRequest *LeaseRequestStruct, leaseResponse *LeaseResponseStruct) globals.Lock() mount, ok = globals.mountMap[leaseRequest.MountID] - if !ok || mount.unmounting { + if !ok || (mount.unmountWGList != nil) { globals.Unlock() err = fmt.Errorf("%s %s", EUnknownMountID, leaseRequest.MountID) return diff --git a/imgr/imgrpkg/utils_test.go b/imgr/imgrpkg/utils_test.go index d05b67de..7516f7bc 100644 --- a/imgr/imgrpkg/utils_test.go +++ b/imgr/imgrpkg/utils_test.go @@ -138,6 +138,7 @@ func testSetup(t *testing.T, overrideConfStrings []string, retryrpcCallbacks int "IMGR.FetchNonceRangeToReturn=100", + "IMGR.MountLimit=10000", "IMGR.OpenFileLimit=100000", "IMGR.MinLeaseDuration=250ms", diff --git a/imgr/imgrpkg/volume.go b/imgr/imgrpkg/volume.go index 7de98c23..f8492fae 100644 --- a/imgr/imgrpkg/volume.go +++ b/imgr/imgrpkg/volume.go @@ -113,6 +113,7 @@ func startVolumeManagement() (err error) { globals.inodeLeaseExpirerWG = nil globals.volumeMap = sortedmap.NewLLRBTree(sortedmap.CompareString, &globals) globals.mountMap = make(map[string]*mountStruct) + globals.unmountsInProgress = 0 err = nil return @@ -183,6 +184,7 @@ func stopVolumeManagement() (err error) { globals.inodeLeaseExpirerWG = nil globals.volumeMap = nil globals.mountMap = nil + globals.unmountsInProgress = 0 err = nil return @@ -603,6 +605,7 @@ func postVolume(storageURL string, authToken string) (err error) { InodeType: ilayout.InodeTypeDir, }) if nil != err { + err = fmt.Errorf("rootDirDirectory.Put(\".\",) failed: %v", err) return } if !ok { @@ -617,15 +620,17 @@ func postVolume(storageURL string, authToken string) (err error) { InodeType: ilayout.InodeTypeDir, }) if nil != err { + err = fmt.Errorf("rootDirDirectory.Put(\"..\",) failed: %v", err) return } if !ok { - err = fmt.Errorf("rootDirDirectory.Put(\".\",) returned !ok") + err = fmt.Errorf("rootDirDirectory.Put(\"..\",) returned !ok") return } _, rootDirInodeObjectOffset, rootDirInodeObjectLength, err = rootDirDirectory.Flush(false) if nil != err { + err = fmt.Errorf("rootDirDirectory.Flush(false) failed: %v", err) return } @@ -664,6 +669,7 @@ func postVolume(storageURL string, authToken string) (err error) { rootDirInodeHeadV1Buf, err = rootDirInodeHeadV1.MarshalInodeHeadV1() if nil != err { + err = fmt.Errorf("rootDirInodeHeadV1.MarshalInodeHeadV1() failed: %v", err) return } @@ -671,6 +677,7 @@ func postVolume(storageURL string, authToken string) (err error) { err = swiftObjectPut(storageURL, authToken, rootDirInodeObjectNumber, postVolumeRootDirDirectoryCallbacks) if nil != err { + err = fmt.Errorf("swiftObjectPut(storageURL, authToken, rootDirInodeObjectNumber, postVolumeRootDirDirectoryCallbacks) failed: %v", err) return } @@ -695,15 +702,17 @@ func postVolume(storageURL string, authToken string) (err error) { InodeHeadLength: uint64(len(rootDirInodeHeadV1Buf)), }) if nil != err { + err = fmt.Errorf("inodeTable.Put(ilayout.RootDirInodeNumber,) failed: %v", err) return } if !ok { - err = fmt.Errorf("inodeTable.Put(RootDirInodeNumber,) returned !ok") + err = fmt.Errorf("inodeTable.Put(ilayout.RootDirInodeNumber,) returned !ok") return } _, superBlockObjectOffset, superBlockObjectLength, err = inodeTable.Flush(false) if nil != err { + err = fmt.Errorf("inodeTable.Flush(false) failed: %v", err) return } @@ -725,6 +734,7 @@ func postVolume(storageURL string, authToken string) (err error) { superBlockV1Buf, err = superBlockV1.MarshalSuperBlockV1() if nil != err { + err = fmt.Errorf("superBlockV1.MarshalSuperBlockV1() failed: %v", err) return } @@ -732,6 +742,7 @@ func postVolume(storageURL string, authToken string) (err error) { err = swiftObjectPut(storageURL, authToken, superBlockObjectNumber, postVolumeSuperBlockInodeTableCallbacks) if nil != err { + err = fmt.Errorf("swiftObjectPut(storageURL, authToken, superBlockObjectNumber, postVolumeSuperBlockInodeTableCallbacks) failed: %v", err) return } @@ -746,11 +757,13 @@ func postVolume(storageURL string, authToken string) (err error) { checkPointV1String, err = checkPointV1.MarshalCheckPointV1() if nil != err { + err = fmt.Errorf("checkPointV1.MarshalCheckPointV1() failed: %v", err) return } err = checkPointWrite(storageURL, authToken, strings.NewReader(checkPointV1String)) if nil != err { + err = fmt.Errorf("checkPointWrite(storageURL, authToken, strings.NewReader(checkPointV1String)) failed: %v", err) return } @@ -2010,16 +2023,18 @@ func (volume *volumeStruct) checkPointWrite(body io.ReadSeeker) (authOK bool, er return } -func (mount *mountStruct) performUnmount(unmountFinishedWG *sync.WaitGroup) { +func (mount *mountStruct) performUnmount() { var ( - inodeNumber uint64 - inodeNumberList *list.List - inodeNumberListElement *list.Element - inodeOpenMapElement *inodeOpenMapElementStruct - leaseReleaseFinishedWG sync.WaitGroup - leaseRequest *leaseRequestStruct - leaseRequestOperation *leaseRequestOperationStruct - ok bool + inodeNumber uint64 + inodeNumberList *list.List + inodeNumberListElement *list.Element + inodeOpenMapElement *inodeOpenMapElementStruct + leaseReleaseFinishedWG sync.WaitGroup + leaseRequest *leaseRequestStruct + leaseRequestOperation *leaseRequestOperationStruct + ok bool + unmountFinishedWG *sync.WaitGroup + unmountFinishedWGListElement *list.Element ) globals.Lock() @@ -2093,11 +2108,24 @@ func (mount *mountStruct) performUnmount(unmountFinishedWG *sync.WaitGroup) { logFatalf("mount.mountListMembership (%v) not one of on{Healthy|AuthTokenExpired|LeasesExpired}MountList") } - mount.volume.mountMapWG.Done() + globals.unmountsInProgress-- - globals.Unlock() + unmountFinishedWGListElement = mount.unmountWGList.Front() + + for unmountFinishedWGListElement != nil { + unmountFinishedWG, ok = unmountFinishedWGListElement.Value.(*sync.WaitGroup) + if !ok { + logFatalf("unmountFinishedWGListElement.Value.(*sync.WaitGroup) returned !ok") + } - if unmountFinishedWG != nil { unmountFinishedWG.Done() + + mount.unmountWGList.Remove(unmountFinishedWGListElement) + + unmountFinishedWGListElement = mount.unmountWGList.Front() } + + mount.volume.mountMapWG.Done() + + globals.Unlock() } diff --git a/release_notes.md b/release_notes.md index b9691293..69d235dd 100644 --- a/release_notes.md +++ b/release_notes.md @@ -1,5 +1,13 @@ # ProxyFS Release Notes +## 2.02.0 (May 6, 2022) + +### Notes: + +This release marks the functional completeness point for ProxyFS. It is also notable in that the supported portions of popular file system test suites (most recently [PJDFSTEST](https://github.com/pjd/pjdfstest)) now verify correctness. It is important to point out the limitations of this functionality, however. While ProxyFS provides a form of network attached storage, it has focused on traditional hierarchical file systems presented over a network. Thus, directories and files, along with symbolic links, are fully supported. Other inode types, however are not. Further, concepts like SETUID and SETGID are explicitly disabled as is the Sticky Bit (traits normally maintained in an inode's MODE attribute). As might be imagined, excluding test cases reliant on special inode attributes as well as inote types other than these three was a non-trivial exercise. But the result has been well worth it. + +Enjoy this distributed file system atop your OpenStack Swift scale out storage! + ## 2.01.0 (March 16, 2022) ### Notes: