POSIX: ensure file and directory inodes are different

this is just an in memory representation.

POSIX wants different inode numbers for the same named file or directory.
This commit is contained in:
chrislu 2022-01-11 23:44:48 -08:00
parent 5bb37d5905
commit 2dcb8cb93b
7 changed files with 43 additions and 34 deletions

View file

@ -103,7 +103,7 @@ func (dir *Dir) Fsync(ctx context.Context, req *fuse.FsyncRequest) error {
func (dir *Dir) newFile(name string) fs.Node {
fileFullPath := util.NewFullPath(dir.FullPath(), name)
fileId := fileFullPath.AsInode()
fileId := fileFullPath.AsInode(false)
dir.wfs.handlesLock.Lock()
existingHandle, found := dir.wfs.handles[fileId]
dir.wfs.handlesLock.Unlock()
@ -122,7 +122,7 @@ func (dir *Dir) newFile(name string) fs.Node {
func (dir *Dir) newDirectory(fullpath util.FullPath) fs.Node {
return &Dir{name: fullpath.Name(), wfs: dir.wfs, parent: dir, id: fullpath.AsInode()}
return &Dir{name: fullpath.Name(), wfs: dir.wfs, parent: dir, id: fullpath.AsInode(true)}
}
@ -316,7 +316,6 @@ func (dir *Dir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.
}
// resp.EntryValid = time.Second
resp.Attr.Inode = fullFilePath.AsInode()
resp.Attr.Valid = time.Second
resp.Attr.Size = localEntry.FileSize
resp.Attr.Mtime = localEntry.Attr.Mtime
@ -342,10 +341,10 @@ func (dir *Dir) ReadDirAll(ctx context.Context) (ret []fuse.Dirent, err error) {
processEachEntryFn := func(entry *filer.Entry, isLast bool) {
if entry.IsDirectory() {
dirent := fuse.Dirent{Name: entry.Name(), Type: fuse.DT_Dir, Inode: dirPath.Child(entry.Name()).AsInode()}
dirent := fuse.Dirent{Name: entry.Name(), Type: fuse.DT_Dir, Inode: dirPath.Child(entry.Name()).AsInode(true)}
ret = append(ret, dirent)
} else {
dirent := fuse.Dirent{Name: entry.Name(), Type: findFileType(uint16(entry.Attr.Mode)), Inode: dirPath.Child(entry.Name()).AsInode()}
dirent := fuse.Dirent{Name: entry.Name(), Type: findFileType(uint16(entry.Attr.Mode)), Inode: dirPath.Child(entry.Name()).AsInode(false)}
ret = append(ret, dirent)
}
}
@ -365,7 +364,7 @@ func (dir *Dir) ReadDirAll(ctx context.Context) (ret []fuse.Dirent, err error) {
// create proper . and .. directories
ret = append(ret, fuse.Dirent{
Inode: dirPath.AsInode(),
Inode: dirPath.AsInode(true),
Name: ".",
Type: fuse.DT_Dir,
})
@ -375,7 +374,7 @@ func (dir *Dir) ReadDirAll(ctx context.Context) (ret []fuse.Dirent, err error) {
if string(dirPath) == dir.wfs.option.FilerMountRootPath {
inode = dir.wfs.option.MountParentInode
} else {
inode = util.FullPath(dir.parent.FullPath()).AsInode()
inode = util.FullPath(dir.parent.FullPath()).AsInode(true)
}
ret = append(ret, fuse.Dirent{
@ -444,7 +443,7 @@ func (dir *Dir) removeOneFile(req *fuse.RemoveRequest) error {
// remove current file handle if any
dir.wfs.handlesLock.Lock()
defer dir.wfs.handlesLock.Unlock()
inodeId := filePath.AsInode()
inodeId := filePath.AsInode(false)
if fh, ok := dir.wfs.handles[inodeId]; ok {
delete(dir.wfs.handles, inodeId)
fh.isDeleted = true

View file

@ -84,11 +84,13 @@ func (dir *Dir) handleRenameResponse(ctx context.Context, resp *filer_pb.StreamR
oldParent, newParent := util.FullPath(resp.Directory), util.FullPath(resp.EventNotification.NewParentPath)
oldName, newName := resp.EventNotification.OldEntry.Name, resp.EventNotification.NewEntry.Name
isDirectory := newEntry.IsDirectory()
oldPath := oldParent.Child(oldName)
newPath := newParent.Child(newName)
oldFsNode := NodeWithId(oldPath.AsInode())
newFsNode := NodeWithId(newPath.AsInode())
newDirNode, found := dir.wfs.Server.FindInternalNode(NodeWithId(newParent.AsInode()))
oldFsNode := NodeWithId(oldPath.AsInode(isDirectory))
newFsNode := NodeWithId(newPath.AsInode(isDirectory))
newDirNode, found := dir.wfs.Server.FindInternalNode(NodeWithId(newParent.AsInode(true)))
var newDir *Dir
if found {
newDir = newDirNode.(*Dir)
@ -113,17 +115,19 @@ func (dir *Dir) handleRenameResponse(ctx context.Context, resp *filer_pb.StreamR
})
// change file handle
inodeId := oldPath.AsInode()
dir.wfs.handlesLock.Lock()
if existingHandle, found := dir.wfs.handles[inodeId]; found && existingHandle != nil {
glog.V(4).Infof("opened file handle %s => %s", oldPath, newPath)
delete(dir.wfs.handles, inodeId)
existingHandle.handle = newPath.AsInode()
existingHandle.f.entry.Name = newName
existingHandle.f.id = newPath.AsInode()
dir.wfs.handles[newPath.AsInode()] = existingHandle
if !isDirectory {
inodeId := oldPath.AsInode(isDirectory)
dir.wfs.handlesLock.Lock()
if existingHandle, found := dir.wfs.handles[inodeId]; found && existingHandle != nil {
glog.V(4).Infof("opened file handle %s => %s", oldPath, newPath)
delete(dir.wfs.handles, inodeId)
existingHandle.handle = newPath.AsInode(isDirectory)
existingHandle.f.entry.Name = newName
existingHandle.f.id = newPath.AsInode(isDirectory)
dir.wfs.handles[newPath.AsInode(isDirectory)] = existingHandle
}
dir.wfs.handlesLock.Unlock()
}
dir.wfs.handlesLock.Unlock()
} else if resp.EventNotification.OldEntry != nil {
// without new entry, only old entry name exists. This is the second step to delete old entry

View file

@ -259,7 +259,7 @@ func (file *File) Fsync(ctx context.Context, req *fuse.FsyncRequest) error {
func (file *File) Forget() {
t := util.NewFullPath(file.dir.FullPath(), file.Name)
glog.V(4).Infof("Forget file %s", t)
file.wfs.ReleaseHandle(t, fuse.HandleID(t.AsInode()))
file.wfs.ReleaseHandle(t, fuse.HandleID(t.AsInode(false)))
}
func (file *File) maybeLoadEntry(ctx context.Context) (entry *filer_pb.Entry, err error) {

View file

@ -18,16 +18,16 @@ type MetaCache struct {
// sync.RWMutex
visitedBoundary *bounded_tree.BoundedTree
uidGidMapper *UidGidMapper
invalidateFunc func(util.FullPath)
invalidateFunc func(fullpath util.FullPath, isDirectory bool)
}
func NewMetaCache(dbFolder string, baseDir util.FullPath, uidGidMapper *UidGidMapper, invalidateFunc func(util.FullPath)) *MetaCache {
func NewMetaCache(dbFolder string, baseDir util.FullPath, uidGidMapper *UidGidMapper, invalidateFunc func(util.FullPath, bool)) *MetaCache {
return &MetaCache{
localStore: openMetaStore(dbFolder),
visitedBoundary: bounded_tree.NewBoundedTree(baseDir),
uidGidMapper: uidGidMapper,
invalidateFunc: func(fullpath util.FullPath) {
invalidateFunc(fullpath)
invalidateFunc: func(fullpath util.FullPath, isDirectory bool) {
invalidateFunc(fullpath, isDirectory)
},
}
}

View file

@ -40,16 +40,16 @@ func SubscribeMetaEvents(mc *MetaCache, selfSignature int32, client filer_pb.Fil
if err == nil {
if message.OldEntry != nil && message.NewEntry != nil {
oldKey := util.NewFullPath(resp.Directory, message.OldEntry.Name)
mc.invalidateFunc(oldKey)
mc.invalidateFunc(oldKey, message.OldEntry.IsDirectory)
if message.OldEntry.Name != message.NewEntry.Name {
newKey := util.NewFullPath(dir, message.NewEntry.Name)
mc.invalidateFunc(newKey)
mc.invalidateFunc(newKey, message.NewEntry.IsDirectory)
}
} else if message.OldEntry == nil && message.NewEntry != nil {
// no need to invaalidate
} else if message.OldEntry != nil && message.NewEntry == nil {
oldKey := util.NewFullPath(resp.Directory, message.OldEntry.Name)
mc.invalidateFunc(oldKey)
mc.invalidateFunc(oldKey, message.OldEntry.IsDirectory)
}
}

View file

@ -109,15 +109,15 @@ func NewSeaweedFileSystem(option *Option) *WFS {
wfs.chunkCache = chunk_cache.NewTieredChunkCache(256, option.getUniqueCacheDir(), option.CacheSizeMB, 1024*1024)
}
wfs.metaCache = meta_cache.NewMetaCache(path.Join(option.getUniqueCacheDir(), "meta"), util.FullPath(option.FilerMountRootPath), option.UidGidMapper, func(filePath util.FullPath) {
wfs.metaCache = meta_cache.NewMetaCache(path.Join(option.getUniqueCacheDir(), "meta"), util.FullPath(option.FilerMountRootPath), option.UidGidMapper, func(filePath util.FullPath, isDirectory bool) {
fsNode := NodeWithId(filePath.AsInode())
fsNode := NodeWithId(filePath.AsInode(isDirectory))
if err := wfs.Server.InvalidateNodeData(fsNode); err != nil {
glog.V(4).Infof("InvalidateNodeData %s : %v", filePath, err)
}
dir, name := filePath.DirAndName()
parent := NodeWithId(util.FullPath(dir).AsInode())
parent := NodeWithId(util.FullPath(dir).AsInode(true))
if dir == option.FilerMountRootPath {
parent = NodeWithId(1)
}

View file

@ -41,8 +41,14 @@ func (fp FullPath) Child(name string) FullPath {
return FullPath(dir + "/" + noPrefix)
}
func (fp FullPath) AsInode() uint64 {
return uint64(HashStringToLong(string(fp)))
func (fp FullPath) AsInode(isDirectory bool) uint64 {
inode := uint64(HashStringToLong(string(fp)))
if isDirectory {
inode = inode - inode%2 // even
} else {
inode = inode - inode%2 + 1 // odd
}
return inode
}
// split, but skipping the root