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 { func (dir *Dir) newFile(name string) fs.Node {
fileFullPath := util.NewFullPath(dir.FullPath(), name) fileFullPath := util.NewFullPath(dir.FullPath(), name)
fileId := fileFullPath.AsInode() fileId := fileFullPath.AsInode(false)
dir.wfs.handlesLock.Lock() dir.wfs.handlesLock.Lock()
existingHandle, found := dir.wfs.handles[fileId] existingHandle, found := dir.wfs.handles[fileId]
dir.wfs.handlesLock.Unlock() 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 { 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.EntryValid = time.Second
resp.Attr.Inode = fullFilePath.AsInode()
resp.Attr.Valid = time.Second resp.Attr.Valid = time.Second
resp.Attr.Size = localEntry.FileSize resp.Attr.Size = localEntry.FileSize
resp.Attr.Mtime = localEntry.Attr.Mtime 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) { processEachEntryFn := func(entry *filer.Entry, isLast bool) {
if entry.IsDirectory() { 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) ret = append(ret, dirent)
} else { } 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) ret = append(ret, dirent)
} }
} }
@ -365,7 +364,7 @@ func (dir *Dir) ReadDirAll(ctx context.Context) (ret []fuse.Dirent, err error) {
// create proper . and .. directories // create proper . and .. directories
ret = append(ret, fuse.Dirent{ ret = append(ret, fuse.Dirent{
Inode: dirPath.AsInode(), Inode: dirPath.AsInode(true),
Name: ".", Name: ".",
Type: fuse.DT_Dir, 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 { if string(dirPath) == dir.wfs.option.FilerMountRootPath {
inode = dir.wfs.option.MountParentInode inode = dir.wfs.option.MountParentInode
} else { } else {
inode = util.FullPath(dir.parent.FullPath()).AsInode() inode = util.FullPath(dir.parent.FullPath()).AsInode(true)
} }
ret = append(ret, fuse.Dirent{ ret = append(ret, fuse.Dirent{
@ -444,7 +443,7 @@ func (dir *Dir) removeOneFile(req *fuse.RemoveRequest) error {
// remove current file handle if any // remove current file handle if any
dir.wfs.handlesLock.Lock() dir.wfs.handlesLock.Lock()
defer dir.wfs.handlesLock.Unlock() defer dir.wfs.handlesLock.Unlock()
inodeId := filePath.AsInode() inodeId := filePath.AsInode(false)
if fh, ok := dir.wfs.handles[inodeId]; ok { if fh, ok := dir.wfs.handles[inodeId]; ok {
delete(dir.wfs.handles, inodeId) delete(dir.wfs.handles, inodeId)
fh.isDeleted = true 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) oldParent, newParent := util.FullPath(resp.Directory), util.FullPath(resp.EventNotification.NewParentPath)
oldName, newName := resp.EventNotification.OldEntry.Name, resp.EventNotification.NewEntry.Name oldName, newName := resp.EventNotification.OldEntry.Name, resp.EventNotification.NewEntry.Name
isDirectory := newEntry.IsDirectory()
oldPath := oldParent.Child(oldName) oldPath := oldParent.Child(oldName)
newPath := newParent.Child(newName) newPath := newParent.Child(newName)
oldFsNode := NodeWithId(oldPath.AsInode()) oldFsNode := NodeWithId(oldPath.AsInode(isDirectory))
newFsNode := NodeWithId(newPath.AsInode()) newFsNode := NodeWithId(newPath.AsInode(isDirectory))
newDirNode, found := dir.wfs.Server.FindInternalNode(NodeWithId(newParent.AsInode())) newDirNode, found := dir.wfs.Server.FindInternalNode(NodeWithId(newParent.AsInode(true)))
var newDir *Dir var newDir *Dir
if found { if found {
newDir = newDirNode.(*Dir) newDir = newDirNode.(*Dir)
@ -113,17 +115,19 @@ func (dir *Dir) handleRenameResponse(ctx context.Context, resp *filer_pb.StreamR
}) })
// change file handle // change file handle
inodeId := oldPath.AsInode() if !isDirectory {
inodeId := oldPath.AsInode(isDirectory)
dir.wfs.handlesLock.Lock() dir.wfs.handlesLock.Lock()
if existingHandle, found := dir.wfs.handles[inodeId]; found && existingHandle != nil { if existingHandle, found := dir.wfs.handles[inodeId]; found && existingHandle != nil {
glog.V(4).Infof("opened file handle %s => %s", oldPath, newPath) glog.V(4).Infof("opened file handle %s => %s", oldPath, newPath)
delete(dir.wfs.handles, inodeId) delete(dir.wfs.handles, inodeId)
existingHandle.handle = newPath.AsInode() existingHandle.handle = newPath.AsInode(isDirectory)
existingHandle.f.entry.Name = newName existingHandle.f.entry.Name = newName
existingHandle.f.id = newPath.AsInode() existingHandle.f.id = newPath.AsInode(isDirectory)
dir.wfs.handles[newPath.AsInode()] = existingHandle dir.wfs.handles[newPath.AsInode(isDirectory)] = existingHandle
} }
dir.wfs.handlesLock.Unlock() dir.wfs.handlesLock.Unlock()
}
} else if resp.EventNotification.OldEntry != nil { } else if resp.EventNotification.OldEntry != nil {
// without new entry, only old entry name exists. This is the second step to delete old entry // 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() { func (file *File) Forget() {
t := util.NewFullPath(file.dir.FullPath(), file.Name) t := util.NewFullPath(file.dir.FullPath(), file.Name)
glog.V(4).Infof("Forget file %s", t) 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) { func (file *File) maybeLoadEntry(ctx context.Context) (entry *filer_pb.Entry, err error) {

View file

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

View file

@ -40,16 +40,16 @@ func SubscribeMetaEvents(mc *MetaCache, selfSignature int32, client filer_pb.Fil
if err == nil { if err == nil {
if message.OldEntry != nil && message.NewEntry != nil { if message.OldEntry != nil && message.NewEntry != nil {
oldKey := util.NewFullPath(resp.Directory, message.OldEntry.Name) oldKey := util.NewFullPath(resp.Directory, message.OldEntry.Name)
mc.invalidateFunc(oldKey) mc.invalidateFunc(oldKey, message.OldEntry.IsDirectory)
if message.OldEntry.Name != message.NewEntry.Name { if message.OldEntry.Name != message.NewEntry.Name {
newKey := util.NewFullPath(dir, 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 { } else if message.OldEntry == nil && message.NewEntry != nil {
// no need to invaalidate // no need to invaalidate
} else if message.OldEntry != nil && message.NewEntry == nil { } else if message.OldEntry != nil && message.NewEntry == nil {
oldKey := util.NewFullPath(resp.Directory, message.OldEntry.Name) 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.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 { if err := wfs.Server.InvalidateNodeData(fsNode); err != nil {
glog.V(4).Infof("InvalidateNodeData %s : %v", filePath, err) glog.V(4).Infof("InvalidateNodeData %s : %v", filePath, err)
} }
dir, name := filePath.DirAndName() dir, name := filePath.DirAndName()
parent := NodeWithId(util.FullPath(dir).AsInode()) parent := NodeWithId(util.FullPath(dir).AsInode(true))
if dir == option.FilerMountRootPath { if dir == option.FilerMountRootPath {
parent = NodeWithId(1) parent = NodeWithId(1)
} }

View file

@ -41,8 +41,14 @@ func (fp FullPath) Child(name string) FullPath {
return FullPath(dir + "/" + noPrefix) return FullPath(dir + "/" + noPrefix)
} }
func (fp FullPath) AsInode() uint64 { func (fp FullPath) AsInode(isDirectory bool) uint64 {
return uint64(HashStringToLong(string(fp))) 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 // split, but skipping the root